package com.netty.tcp;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class MessageDecoder extends ByteToMessageDecoder {

    //需要确认是否线程安全
    /**是否在读取头部*/
    private volatile AtomicBoolean readComplete = new AtomicBoolean(true);
    /**报文的长度*/
    private volatile AtomicInteger msglen = new AtomicInteger(0);
    /**报文本身*/
    private MsgObj obj = null;
    private int offset = 8;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        //System.out.println("decode");
        if (readComplete.get()){
            byte[] headbuff = new byte[offset];
            in.readBytes(headbuff);
            String header = new String(headbuff);
            //log.info("报文长度：{}",header);
            msglen = new AtomicInteger(Integer.valueOf(header));
            if (obj == null){
                obj = new MsgObj();
                obj.setHeader(msglen.get());
                obj.setBody("");
            }
        }
        int bd = in.readableBytes() ;
        //考虑拆包
        if (bd < msglen.get() ){
            // 拆包继续读
            readComplete.set(false);
            msglen.set(msglen.get() - bd);
           // log.info("发生【拆包】,本次读取[{}],还需要环读取剩下的报文[{}]",bd,msglen.get());
            byte[] tmpbody = new byte[bd];
            in.readBytes(tmpbody);
            String body = obj.getBody();
            body = body + new String(tmpbody);
            obj.setBody(body);

        }else if (bd == msglen.get()){
            msglen.set(msglen.get() - bd);
           // log.info("发生【拆包】,本次读取[{}],还需要环读取剩下的报文[{}]",bd,msglen.get());
            byte[] tmpbody = new byte[bd];
            in.readBytes(tmpbody);
            String body = obj.getBody();
            body = body + new String(tmpbody);
            obj.setBody(body);

            //ctx.writeAndFlush(obj);
            out.add(obj);
            //重置
            if (msglen.get() == 0){
                readComplete.set(true);
                this.msglen.set(0);
                obj=null;
            }

        }else {
            // 考虑粘包
            byte[] tmpbody = new byte[msglen.get()];
            log.info("发生【粘包】,本次读取[{}],还需要环读取剩下的报文[{}]",bd,msglen.get());
            in.readBytes(tmpbody);
            String body = obj.getBody();
            body = body + new String(tmpbody);
            obj.setBody(body);

            //ctx.writeAndFlush(obj);
            out.add(obj);
            // 重置
            readComplete.set(true);
            this.msglen.set(0);
            obj=null;
        }
    }
}
